<?php

namespace App\Listeners;

use Illuminate\Database\Events\QueryExecuted;

class QueryListener
{
    private static $instance;

    public static function getInstance(): self
    {
        if (null === static::$instance) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    private $printSqlLogEnv;

    private $ms = [];

    /**
     * Create the event listener.
     */
    public function __construct()
    {
        $this->printSqlLogEnv = config('app.log_sql');
    }

    /**
     * Handle the event.
     *
     * @param QueryExecuted $event
     */
    public function handle(QueryExecuted $event)
    {
        if ($this->printSqlLogEnv) {
            static::getInstance()->genLog($event);
        }
    }

    public function genLog(QueryExecuted $event)
    {
        $path = request()->path();
        $sql = $event->sql;
        foreach ($event->bindings as $val) {
            $sql = preg_replace('/\?/', $this->queryValueToString($val), $sql, 1);
        }

        $this->ms[] = $event->time;
        $log = '['.count($this->ms).']['.date('H:i:s').']['.$path.'] '.$sql.' ['.$event->time.'ms]';
        $this->writeLog($log);
    }

    private function queryValueToString($val)
    {
        if (is_string($val)) {
            return "'{$val}'";
        } elseif (is_bool($val)) {
            return (string) (int) $val;
        } else {
            return (string) $val;
        }
    }

    private function writeLog($log)
    {
        if (true === $this->printSqlLogEnv || 'stderr' === $this->printSqlLogEnv) {
            error_log($log);
        }
        if (true === $this->printSqlLogEnv || 'log' === $this->printSqlLogEnv) {
            $file = new \SplFileObject(storage_path('logs/sql_'.date('Y-m-d').'.log'), 'a');
            $file->fwrite($log."\n");
        }
    }

    public function __destruct()
    {
        if (count($this->ms)) {
            $this->writeLog('['.request()->path().'] total time '.array_sum($this->ms).'ms');
        }
    }
}
